﻿using System;
using System.Diagnostics.Contracts;

namespace Isuka.Iteration
{

    /// <summary>
    /// C++ の前方反復子に近いもの。
    /// 列挙子との違いは以下の通り
    /// <list type="number">
    /// <item><description>事前に MoveNext を呼び出す必要が無い</description></item>
    /// <item><description>コピーして位置情報を保存可能</description></item>
    /// </list>
    /// </summary>
    /// <remarks>
    /// 旧 isuka の Iterator は、C++ を意識しすぎて使い勝手が悪くなっていたため、全面的に再構築。
    /// </remarks>
    public partial interface IIterator
        : ICloneable
    {
        /// <summary>
        /// 指定された値だけ列挙を行う。
        /// </summary>
        /// <param name="diff"></param>
        /// <returns>移動できたかどうか</returns>
        bool Advance(int diff);

        /// <summary>
        /// コンテナー先頭からの絶対位置。
        /// ただし、コンテナーを持たない場合や、先頭が無い場合は null
        /// </summary>
        [Pure]
        int? Bias { get; }

        /// <summary>
        /// 反復子の親となるコンテナー。
        /// NULL の場合もある。
        /// </summary>
        [Pure]
        object Container { get; }

        /// <summary>
        /// 反復子が指す要素
        /// </summary>
        [Pure]
        object Current { get; }

        /// <summary>
        /// 反復子が同じオブジェクトを指しているかどうかを比較する。
        /// なお、null と比較された場合、コンテナーの終端が指定されたものとして扱い、
        /// InRange が true の場合は false を返し、InRange が false の場合 true を返すように実装する。
        /// </summary>
        /// <param name="other">他の反復子</param>
        /// <returns></returns>
        [Pure]
        bool Equals(IIterator other);

        /// <summary>
        /// 反復子間の距離を求める。
        /// 型が異なる場合や比較不可能な場合は NULL を返す。
        /// </summary>
        /// <param name="other"></param>
        /// <returns>反復子間の距離。比較不可能な場合 NULL</returns>
        [Pure]
        int? Distance(IIterator other);

        /// <summary>
        /// 反復子が有効範囲内かどうか。
        /// </summary>
        [Pure]
        bool InRange { get; }

        /// <summary>
        /// 次へ移動
        /// </summary>
        void MoveNext();
    }

    /// <summary>
    /// C++ の反復子のような列挙子
    /// ForwardTraversal + Readable
    /// </summary>
    /// <typeparam name="T">値の型</typeparam>
    /// <remarks>
    /// 旧 isuka の Iterator は、C++ を意識しすぎて使い勝手が悪くなっていたため、全面的に再構築。
    /// </remarks>
    public partial interface IIterator<T>
        : IIterator
    {
        /// <summary>
        /// 現在の要素を取得
        /// </summary>
        [Pure]
        new T Current { get; }
    }

    /// <summary>
    /// 値を設定可能な反復子
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public interface IReWritableIterator<T>
        : IIterator<T>
    {
        new T Current { get; set; }
    }

    #region IIterator contract binding

    [ContractClass(typeof(IIteratorContract))]
    public partial interface IIterator { }

    [ContractClassFor(typeof(IIterator))]
    abstract class IIteratorContract : IIterator
    {
        #region IIterator メンバー

        public bool Advance(int diff)
        {
            throw new NotImplementedException();
        }

        public int? Bias
        {
            get { throw new NotImplementedException(); }
        }

        public object Container
        {
            get { throw new NotImplementedException(); }
        }

        public object Current
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        public int? Distance(IIterator other)
        {
            Contract.Requires<ArgumentNullException>(other != null, "other");

            throw new NotImplementedException();
        }

        public bool Equals(IIterator other)
        {
            /*
             * other が null の場合、InRange の逆を返すこと
             */
            Contract.Ensures(other != null || Contract.Result<bool>() == !InRange);
            throw new NotImplementedException();
        }

        public bool InRange
        {
            get { throw new NotImplementedException(); }
        }

        public void MoveNext()
        {
            throw new NotImplementedException();
        }

        #endregion

        #region ICloneable メンバー

        public object Clone()
        {
            throw new NotImplementedException();
        }

        #endregion
    }
    #endregion

}
